<?php

// Try to include Types file.
if( ( require_once( "BuxterPHPClient.Types.inc.php" ) ) != 1 || ( require_once( dirname( __FILE__ ) . "/BuxterPHPClient.Types.inc.php" ) ) != 1 ) {
	die( "Failed to include BuxterPHPClient.Types.inc.php; file should be in same directory" );
}

/**
 * This is the PHP client implementation for the Buxter API.
 *
 * @author thijs.reus
 * @author andrei.martchouk
 * @author matthias.gall
 * @author natasha.martchouk
 *
 */
class BuxterPHPClient {
	/** The API configuration ID as displayed on the Buxter applications screen. */
	private $apiConfigurationID;
	/** The generated secret key as displayed on the Buxter applications screen. */
	private $secretKey;
	/** A <code>SoapClient</code> used to communicate with Buxter. */
	private $soapClient;

	/** Holds the mapping of XSD types to PHP classes. */	
	private static $classMappings = array( "TransactionInfo" => "TransactionInfo",
											"CreateTransaction_Request" => "CreateTransactionRequest",
											"CreateTransaction_Response" => "CreateTransactionResponse",
											"GetTransactionStatus_Request" => "GetTransactionStatus",
											"GetTransactionStatus_Response" => "GetTransactionStatusResponse",
											"CancelTransaction_Request" => "CancelTransactionRequest",
											"CancelTransaction_Response" => "CancelTransactionResponse"
											);

	/**
	 * Creates a Buxter PHP client usable for the Buxter production application.
	 *
	 * @param apiConfigurationID
	 * @param secretKey
	 */
	public static function createClient( $apiConfigurationID, $secretKey ) {
		$client = new BuxterPHPClient( $apiConfigurationID, $secretKey,
										"https://buxter.clickandbuy.com/moneywallet/ds/api/1.0/buxter-1.0.wsdl"
										);
		return $client;
	}

	/**
	 * Creates a Buxter PHP client usable for the Buxter sandbox application.
	 *
	 * @param apiConfigurationID
	 * @param secretKey
	 */
	public static function createSandboxClient( $apiConfigurationID, $secretKey ) {
		$client = new BuxterPHPClient( $apiConfigurationID, $secretKey,
										"https://buxter.clickandbuy.com/moneywallet/ds/api/1.0/buxter-1.0.wsdl",
										"https://wallet.clickandbuy-s1.com/moneywallet/ds/api/1.0/soap"
										);
		return $client;
	}
	
	/**
	 * Creates a Buxter PHP client usable for the given WSDL and endpoint location.
	 *
	 * @param apiConfigurationID
	 * @param secretKey
	 * @param wsdlUrl
	 * @param endpointUrl
	 */
	public static function createDevelopmentClient( $apiConfigurationID, $secretKey, $wsdlUrl, $endpointUrl ) {
		$client = new BuxterPHPClient( $apiConfigurationID, $secretKey, $wsdlUrl, $endpointUrl );
		return $client;
	}
	
	/**
	 * Hidden c'tor, please use the <code>create*</code> methods to instantiate a new client.
	 * Creates a new instance of the <code>BuxterPHPClient</code>. 
	 *
	 * @param apiConfigurationID
	 * @param secretKey
	 * @param wsdlUrl
	 * @param endpointUrl
	 */
	private function __construct( $apiConfigurationID, $secretKey, $wsdlUrl, $endpointUrl ) {
		$this->apiConfigurationID = $apiConfigurationID;
		$this->secretKey = $secretKey;
		$this->soapClient = new SoapClient( $wsdlUrl,
												array(
													"classmap" => BuxterPHPClient::$classMappings,
													"location" => $endpointUrl
												)
											);
	}
	
	/**
	 * Creates a new transaction link which can then be displayed or used for a redirect by the
	 * calling application.
	 *
	 * @param amount the amount to purchase in the smallest possible unit, e.g. for a 1 USD purchase
	 *   this would mean "10000" for 10000 cents.
	 * @param currency the currency as a 3-letter ISO 4217 currency code, e.g. "EUR" or "USD".
	 * @param title the title of the purchase.
	 * @param description a more detailled description or subtitle (optional).
	 * @param buyerFbUID the Facebook user ID of the buyer.
	 * @param redirectURL the URL to redirect the buyer to after the purchase.
	 * @param externalID the callers internal transaction ID. Must be unique; if unused, pass e.g.
	 *   <code>microtime()</code> as a string.
	 * @return the <code>CreateTransactionResponse</code> object containing the
	 *   <code>transactionID</code> and <code>redirectURL</code> of the created transaction.
	 */
	public function createTransactionLink( $amount, $currency, $title, $description, $buyerFbUID, $redirectURL, $externalID ) {
		$money = new Money( $amount, $currency );
		$request = new CreateTransactionRequest( $this->apiConfigurationID,
													$money,
													$title,
													$description,
													$buyerFbUID,
													$redirectURL,
													$externalID,
													$this->secretKey
												);
		try {
			$response = $this->soapClient->CreateTransaction( $request );
		} catch( SoapFault $e ) {
			throw new ErrorResponse( $e );
		}
		
		return $response;
	}
	
	/**
	 * Queries for the status of a transaction using the Buxter transaction ID which was returned
	 * in the <code>createTransactionLink</code> call. This should be called before the payed
	 * content or functionality is actually delivered.
	 *
	 * @param transactionID the Buxter transaction ID returned by <code>createTransactionLink</code>.
	 * @return the status as a string; content should only be delivered if "SUCCESS" is returned.
	 */
	public function queryTransactionStatusByTransactionID( $transactionID ) {
		$request = new GetTransactionStatusRequest( $this->apiConfigurationID,
													$transactionID,
													false,
													$this->secretKey
												);
		return $this->queryTransactionStatus( $request );
	}
	
	/**
	 * Queries for the status of a transaction using the callers external ID which was passed to
	 * the <code>createTransactionLink</code> call. This should be called before the payed
	 * content or functionality is actually delivered.
	 *
	 * @param transactionID the Buxter transaction ID returned by <code>createTransactionLink</code>.
	 * @return the status as a string; content should only be delivered if "SUCCESS" is returned.
	 */
	public function queryTransactionStatusByExternalID( $externalID ) {
		$request = new GetTransactionStatusRequest( $this->apiConfigurationID,
													$externalID,
													true,
													$this->secretKey
												);
		return $this->queryTransactionStatus( $request );
	}
	
	private function queryTransactionStatus( $request ) {
		try {
			$response = $this->soapClient->GetTransactionStatus( $request );
		} catch( SoapFault $e ) {
			throw new ErrorResponse( $e );
		}
		
		return $response->transactionStatus;
	}
	
	/**
	 * Cancels a transaction using the Buxter transaction ID which was returned in the
	 * <code>createTransactionLink</code> call.
	 *
	 * @param the Buxter transaction ID returned by <code>createTransactionLink</code>.
	 * @return the new status as a string; should be "CANCELLED" now.
	 */
	public function cancelTransactionByTransactionID( $transactionID ) {
		$request = new CancelTransactionRequest( $this->apiConfigurationID,
													$transactionID,
													$this->secretKey
												);
		try {
			$response = $this->soapClient->CancelTransaction( $request );
		} catch( SoapFault $e ) {
			throw new ErrorResponse( $e );
		}
		
		return $response->transactionStatus;
	}
}

?>
